﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using CloudAppMonitor.Data;
using CloudAppMonitor.Library;

namespace CloudAppMonitor.Controls
{
    internal partial class PerformanceGraph : UserControl
    {
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IEnumerable<CounterValue> CounterValues { get; set; }

        [EditorBrowsable(EditorBrowsableState.Never)]
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IEnumerable<MonitoredPerformanceCounter> Counters { get; set; }

        [EditorBrowsable(EditorBrowsableState.Never)]
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public DateTime NewestDate { get; set; }

        public PerformanceGraph()
        {
            InitializeComponent();

            Counters = new List<MonitoredPerformanceCounter>();
            CounterValues = new List<CounterValue>();

            DoubleBuffered = true;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (DesignMode)
            {
                e.Graphics.DrawString(Name, Font, Brushes.Black, 3, 3);

                return;
            }

            DrawGridLines(e.Graphics);

            int zeroLocation = Height - 11;
            float graphScale = (float)zeroLocation / 100;

            MonitoredPerformanceCounter selectedCounter = ((Monitor)ParentForm).SelectedPerformanceCounter;

            var orderedCounters = from c in Counters
                                  orderby c == selectedCounter ? 1 : 0
                                  select c;

            foreach (MonitoredPerformanceCounter counter in orderedCounters)
            {
                var counterTrace = from cv in CounterValues
                                   where cv.CounterId == counter.CounterId && cv.RoleInstanceId == counter.RoleInstanceId
                                   orderby cv.EventTime descending
                                   select cv;

                Point previousPoint = new Point();
                bool firstPoint = true;
                int xPosition = Width;

                int penWidth = 1;
                Color penColor = counter.StyleColor;

                if (selectedCounter == counter)
                {
                    penWidth = 2;
                    penColor = Color.Black;
                }

                using (Pen counterPen = new Pen(penColor, penWidth))
                {
                    foreach (CounterValue value in counterTrace.Take(Width - 23))
                    {
                        int yPoint = zeroLocation - (int)(value.Value * counter.Scale * graphScale);

                        if (yPoint < 0)
                        {
                            yPoint = 0;
                        }

                        if (yPoint > zeroLocation)
                        {
                            yPoint = zeroLocation;
                        }

                        Point currentPoint = new Point();

                        currentPoint.X = Width - (int)NewestDate.Subtract(value.EventTime).TotalMinutes;
                        currentPoint.Y = yPoint;

                        if (firstPoint)
                        {
                            previousPoint = currentPoint;
                            firstPoint = false;
                        }

                        e.Graphics.DrawLine(counterPen, currentPoint, previousPoint);

                        previousPoint = currentPoint;
                    }
                }
            }
        }

        private void DrawGridLines(Graphics g)
        {
            float actualHeight = Height - 10;
            int xOffset = 23;

            float yScaleIncrement;
            int yValueDecrement;

            //Draw yscale
            if (actualHeight > 200)
            {
                yScaleIncrement = actualHeight / 10;
                yValueDecrement = 1;
            }
            else
            {
                yScaleIncrement = actualHeight / 5;
                yValueDecrement = 2;
            }

            int yValue = 10;

            for (float yScalePos = 0; yScalePos < actualHeight; yScalePos += yScaleIncrement)
            {
                if (yScalePos == 0)
                {
                    g.DrawString("100", Font, Brushes.Black, 0, -3);
                }
                else
                {
                    g.DrawString(string.Format(" {0}0", yValue), Font, Brushes.Black, 0, yScalePos - 8);

                    g.DrawLine(Pens.LightGray, xOffset, yScalePos, Width, yScalePos);
                }

                yValue -= yValueDecrement;
            }

            if (NewestDate != DateTime.MinValue)
            {
                //Draw the x scale
                int hourPos = Width - NewestDate.Minute;
                DateTime currentLineTime = NewestDate.ToLocalTime().AddMinutes(-NewestDate.Minute);

                while (hourPos > xOffset)
                {
                    if (currentLineTime.Hour == 0)
                    {
                        g.DrawString(string.Format("{0:MM/dd}", currentLineTime), Font, Brushes.Black, hourPos - 16, actualHeight - 1);

                        g.DrawLine(Pens.DarkGray, hourPos, 0, hourPos, actualHeight - 1);
                    }
                    else
                    {
                        g.DrawString(string.Format("{0,2}", currentLineTime.Hour), Font, Brushes.Black, hourPos - 8, actualHeight - 1);

                        g.DrawLine(Pens.LightGray, hourPos, 0, hourPos, actualHeight - 1);
                    }

                    hourPos -= 60;
                    currentLineTime = currentLineTime.AddHours(-1);
                }
            }

            //Draw Axis
            g.DrawLine(Pens.Black, xOffset, 0, xOffset, actualHeight);
            g.DrawLine(Pens.Black, xOffset, actualHeight, Width, actualHeight);
        }
    }
}
